﻿"""
因子选股策略回测示例
使用bond_factor_strategy.py中的策略进行回测
使用真实数据库数据
"""
import os
import sys
import time
project_root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.append(project_root)
from datetime import datetime, timedelta
import pandas as pd
import numpy as np
from loguru import logger
from typing import List,Dict
from visualization.performance import PerformanceAnalyzer, PerformanceVisualizer
from engine.object import BacktestResultSchema
from engine.engine import BacktestEngine
from engine.assets import Bond
from engine.constant import AssetType,OffsetType
from engine.utility import generate_backtest_report
from database.mysqldb import MysqlDatabase
from strategy.examples.bond_factor_strategy import BondFactorStrategy

def main(params:List[Dict],start,end):
    # 创建回测引擎，使用真实的MySQL数据库
    initial_capital = 200000000
    engine = BacktestEngine(commission_rate=0.0001, 
                            slippage_rate=0.000,
                            database=MysqlDatabase(),
                            start=start,
                            end=end,
                            fill_vol_cap_pct=0.1,
                            initial_capital=initial_capital)
    
    res_full = []
    npv_full = []
    for param in params:
        logger.info(f"开始运行回测参数:{param}")
        res = {}
        engine.reset_results()
        # 创建策略实例
        strategy = BondFactorStrategy(
            name="债券因子选股策略",
            score_floor_buffer = param['score_floor'],
            # score_floor_buffer = max(int(param['score_floor']*0.25*10)/10,0),
            # score_floor_buffer = 0.003,
            **param
        )
        
        
        
        # 设置回测引擎
        engine.set_strategy(strategy)
        engine.initialize() #引擎初始化
        if not engine.market_data:
            # 如果已经加载了市场数据则不需要重复进行加载
            engine.load_data() #加载数据
        
        
        # 运行回测
        logger.info("开始运行回测...")
        results:pd.DataFrame[BacktestResultSchema] = engine.run_backtest()
        # 净值曲线记录
        nvp = results[['date','total_value']].set_index('date').\
                    rename(columns={'total_value':f'{param['score_floor']}_{param['rebalance_interval']}'})
        npv_full.append(nvp/initial_capital)


        # 创建性能分析器和可视化器
        analyzer = PerformanceAnalyzer(results)
        visualizer = PerformanceVisualizer(analyzer)
        metrics = analyzer.metrics
        
        report_name = f'.\\tests\\report_{str(start)}_{str(end)}_{'_'.join([str(i) for i in param.values()])}.html'
        # 生成HTML报告
        visualizer.export_html_report(report_name)
    
        print("\n=== 回测结果 ===")
        print("回测完成!")
        print("指标:", metrics)
        res.update(param)
        res.update(metrics)
        res_full.append(res)
    npv_full = pd.concat(npv_full,axis=1)
    npv_full.to_excel(f'npv_{start}_{end}.xlsx')
        
    return res_full
if __name__ == "__main__":
    from itertools import product
    from visualization.performance import create_parameter_surface_html

    for start,end in (("20210601","20230131"),("20230115","20241030")):
        categorys = [None,]
        params = product(
            categorys,
            [(0.004,0.05),],
            [3,],
            )
        # for start,end in (("20210601","20230131"),):
        #     categorys = [None,]
        #     params = product(
        #         categorys,
        #         [0.005,],
        #         [5,],
        #         )
        
        params = [ dict(category=param[0],
                        score_floor=param[1][0],
                        score_cap=param[1][1],
                        rebalance_interval=param[2],
                        ) for param in params]

        res = main(params,start,end)
        res_df = pd.DataFrame(res)
        # logger.info(res)
        res_df.to_excel(f'.\\tests\\backtest_result_{start}_{end}.xlsx')
        # res_df.to_excel(f'backtest_result_{start}_{end}.xlsx')
        # 在参数扫描完成后生成可视化
        # for category in categorys:
        #     create_parameter_surface_html(
        #         param_results=res,  # 优化结果列表
        #         x_param="score_floor", 
        #         y_param="rebalance_interval",
        #         title=f"债券因子策略参数优化 ({start}-{end})",
        #         filename=f".\\tests\\param_optimization_{start}_{end}_{category}.html"
        #     )
        # for category in categorys:
        #     create_parameter_surface_html(
        #         param_results=res,  # 优化结果列表
        #         x_param="score_floor", 
        #         y_param="rebalance_interval",
        #         title=f"债券因子策略参数优化 ({start}-{end})",
        #         filename=f"param_optimization_{start}_{end}_{category}.html"
        #     )